Release 10.1A: OpenEdge Development:
Web Services


Reusing an unchanged SOAP response header

This example shows how you might handle a SOAP header that you first encounter in the response message returned from the Web service, then use unchanged as the SOAP header for the next request. This is an example of the header returned from the Web service:

SOAP response header to be reused
<soap:Envelope> 
       . . . 
        <soap:Header> 
                <AuthHeader xmlns="http://ServiceHost/SOAPHeader"> 
                        <AccessID>XYZZY</AccessID> 
                </AuthHeader> 
        </soap:Header> 
       . . . 
</soap:Envelope > 

It contains one header entry, AuthHeader, that contains a value used as an access key (AccessID). This type of header might be used when the Web service and client maintain a consistent context for each other between requests.

This is the mainline of a procedure that invokes the Web service to reuse the response header:

Invoking a request that reuses an unchanged SOAP response header
/* 
 * SOAPHeader1.p 
 * 
 * Calls a ficticious Web service, first to request access, which  
 * gets back a SOAP response header containing an AccessID, 
 * and sends the response header back as part of a new request  
 * using the required access credential that allows the Web service  
 * to respond appropriately to the follow-up request.  
 *  
 * The Web service has only one service and port available. 
 */ 
/*1*/ 
/* Define local variables */ 
DEFINE VARIABLE hWebSrvc    AS HANDLE. 
DEFINE VARIABLE hPortType   AS HANDLE. 
DEFINE VARIABLE cResponse   AS CHARACTER FORMAT "x(72)". 
DEFINE VARIABLE g_header    AS HANDLE.  
/* Create the Web service server object */ 
CREATE SERVER hWebSrvc. 
/* Connect to the Web service */ 
hWebSrvc:CONNECT("-WSDL 
                  http://ServiceHost/SOAPHeader/HeaderExample.asmx?wsdl"). 
/* Get the method, set the port type */ 
RUN HeadersSoap SET hPortType ON hWebSrvc. 
/*2*/ 
/* Associate the req. & resp. callbacks with the port type */  
hPortType:SET-CALLBACK-PROCEDURE("REQUEST-HEADER", "ReqHandler").  
hPortType:SET-CALLBACK-PROCEDURE("RESPONSE-HEADER", "RespHandler"). 
/*3*/ 
/* Invoke the Web service with no header and display the results */ 
RUN OpenAccess IN hPortType (OUTPUT cResponse). 
DISPLAY cResponse LABEL "WS response" WITH FRAME aaa. 
/*4*/ 
/* Go again with the AccessID set from previous response header */ 
cResponse = "". 
RUN HelloWorld IN hPortType (OUTPUT cResponse). 
DISPLAY cResponse LABEL "WS response" WITH FRAME bbb. 
/*5*/ 
DELETE OBJECT g_header. 
DELETE OBJECT hPortType. 
hWebSrvc:DISCONNECT(). 
DELETE OBJECT hWebSrvc. 
/**************** Internal Procedures ****************/ 

This code:

  1. Defines several mainline variables, including a global handle to reference the reused SOAP header (g_header).
  2. Registers the request header (ReqHandler) and response header (RespHandler) handlers after connecting to the Web service and instantiating the HeaderSoap port type procedure object.
  3. Runs the OpenAccess procedure to invoke the Web service operation that returns the AccessID value in the SOAP response header (see the "Response header handler for returning a header for reuse" section).
  4. Runs the HelloWorld procedure to invoke the next Web service operation, passing back the SOAP response header to the Web service unchanged as the SOAP request header (see the "Request header handler for reusing a header" section).
  5. Cleans up the global objects maintained in its context and disconnects from the Web service. Note that one of the objects it deletes is the original SOAP response header saved by the response header handler during execution of the OpenAccess procedure.
Response header handler for returning a header for reuse

This is the SOAP response header handler (RespHandler) that returns the header that is reused for passing around the AccessID value:

Response header handler saving a SOAP response header for reuse
PROCEDURE RespHandler: /*1*/  
    DEFINE INPUT PARAMETER hHeader    AS HANDLE. 
    DEFINE INPUT PARAMETER cNamespace AS CHARACTER. 
    DEFINE INPUT PARAMETER cLocalNS   AS CHARACTER. 
         
        /* If the g_header global variable  
           is valid coming in, it has already been set  
           in a previous response, therefore, delete  
           the unnecessary response header object. 
           Otherwise, set g-header to the response  
           header object to pass back to the request  
           header handler on subsequent requests. */ 
    IF NOT VALID-HANDLE(g_header) THEN /*2a*/ /* first response */ 
        g_header = hHeader. 
    ELSE DO: /*2b*/ /* all subsequent responses */ 
        DELETE OBJECT hHeader.  
    END.  
END PROCEDURE. 

This code:

  1. Receives the SOAP response header using the hHeader parameter.
  2. Tests if the global header handle (g_header) already references a valid object:
    1. If it does not reference an object, the handler must be running as part of the initial call to OpenAccess and thus saves the input SOAP header object (hHeader) to the global context (g_header) for use by subsequent requests. From this moment forward, all requests to the Web service discard the header object input to the response handler as unnecessary.
    2. If it does reference an object, the handle must already reference a SOAP response header returned in a prior request (the call to OpenAccess) and has no need of a subsequent response header. It therefore deletes the unnecessary SOAP header object returned to the handler through the hHeader parameter in order to prevent a memory leak accumulating in subsequent requests.
Request header handler for reusing a header

This is the SOAP request header handler (ReqHandler) that reuses the initial SOAP response header to pass the AccessID value between the client and Web service:

Request header handler reusing a saved SOAP response header
PROCEDURE ReqHandler: /*1*/ 
    DEFINE OUTPUT PARAMETER hHeader    AS HANDLE. 
    DEFINE INPUT  PARAMETER cNamespace AS CHARACTER. 
    DEFINE INPUT  PARAMETER cLocalNS   AS CHARACTER. 
    DEFINE OUTPUT PARAMETER lDeleteOnDone AS LOGICAL. 
        /* The IF test determines if this is the first request. 
           If it is, then g_header is not set and hHeader is set 
           to ? to ensure that no header is sent. 
           g_header gets set when the response header is 
           returned, so a subsequent pass through this code takes 
           the previous response header and sends it as the 
           current request header. */  
    IF NOT VALID-HANDLE (g_header) THEN DO: /*2a*/ /* first request */  
        hHeader = ?.  
        lDeleteOnDone = TRUE.  
    END. 
    ELSE DO: /*2b*/ /* all subsequent requests */  
        hHeader = g_header.  
        lDeleteOnDone = FALSE.  
    END. 
END PROCEDURE. 

This code:

  1. Sends the SOAP request header for the HelloWorld request (and any request run after running OpenAccess).
  2. Tests if the global header handle (g_header) references a valid object:
    1. If it does not reference an object, the request handler must be running as part of the initial call to OpenAccess and sets the output parameters to ensure that no initial SOAP request header is sent.
    2. If it does reference an object, the handler passes the global header object as output using the request header parameter (hHeader) and ensures that the object is not deleted (saving it for use in any further request).

Copyright © 2005 Progress Software Corporation
www.progress.com
Voice: (781) 280-4000
Fax: (781) 280-4095